package com.example.common.enums;

import cn.hutool.core.util.DesensitizedUtil;

import java.util.function.Function;

/**
 * 脱敏类型枚举
 * 需要脱敏的字段，在字段上加上@Desensitized注解，并设置类型
 * <p>
 * 为什么使用 Function 函数式接口
 * 在这个枚举类中，每个枚举值都持有一个Function<String, String>类型的desensitizer字段，
 * 用于定义如何对特定类型的数据进行脱敏处理。使用Function函数式接口的原因有以下几点：
 * 统一接口：所有脱敏操作都有相同的函数签名：接收一个字符串参数，返回一个处理后的字符串。
 * 使用Function<String, String>可以为所有脱敏操作提供统一的接口。
 * 行为参数化：通过函数式接口，可以将脱敏逻辑作为参数传递，实现行为参数化。
 * 每个枚举值都可以有自己的脱敏实现，但都遵循相同的调用方式。
 * 简化代码：使用Lambda表达式可以简洁地定义简单的脱敏逻辑，比如：
 * USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2"))：
 * 将姓名的第二个字符替换为*
 * PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"))：
 * 将手机号中间4位替换为****
 * 方法引用支持：对于复杂的脱敏逻辑，可以使用方法引用，比如：
 * PASSWORD(DesensitizedUtil::password)：引用DesensitizedUtil类的password方法
 * CAR_LICENSE(DesensitizedUtil::carLicense)：引用carLicense方法
 * 易于扩展：如果需要添加新的脱敏类型，只需添加新的枚举值并提供相应的脱敏函数即可，
 * 无需修改现有代码。
 */
public enum DesensitizedType {

    /**
     * 用户名
     * 脱敏规则：将用户名的第二个字符替换为*
     * regex 正则表达式：(\\S)\\S(\\S*)
     * replacement是替换的字符串
     * $1*$2 是替换的字符串，其中$1表示匹配到的第一个字符，$2表示匹配到的第二个字符。
     */
    USERNAME((s) -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
    /**
     * 密码，全部字符都用*代替
     */
    PASSWORD(DesensitizedUtil::password),

    /**
     * 身份证，中间10位星号替换
     */
    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1** **** ****$2")),

    /**
     * 手机号，中间4位星号替换
     */
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),

    /**
     * 电子邮箱，仅显示第一个字母和@后面的地址显示，其他星号替换
     */
    EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),

    /**
     * 银行卡号，保留最后4位，其他星号替换
     */
    BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),

    /**
     * 车牌号码，包含普通车辆、新能源车辆
     * carLicense 是一个工具类，用于对车牌号进行脱敏处理
     */
    CAR_LICENSE(DesensitizedUtil::carLicense);

    /**
     * desensitizer 统一接口：所有脱敏操作都有相同的函数签名：
     * 接收一个字符串参数，返回一个处理后的字符串。
     */
    private final Function<String, String> desensitizer;

    DesensitizedType(Function<String, String> desensitizer) {
        this.desensitizer = desensitizer;
    }

    public Function<String, String> getDesensitizer() {
        return desensitizer;
    }
}
